package top.xia17.plugins.fast.common.database.mybatis.extension;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import jakarta.validation.constraints.NotNull;
import top.xia17.plugins.fast.common.database.CrudServiceExpand;
import top.xia17.plugins.fast.common.database.CrudServiceExpandContext;
import top.xia17.plugins.fast.common.database.mybatis.exception.EntityNotFoundException;
import top.xia17.plugins.fast.common.exceptions.BadRequestException;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Optional;

/**
 * mybatis-plus 的基础Service的实现
 *
 * @author xia17
 * @since 2021/12/1 15:16
 */
public class IbatisServiceImpl<T extends IbatisEntity<ID>, ID extends Serializable, M extends BaseMapper<T>> extends CrudServiceExpandContext implements IbatisService<T, ID>,
        CrudServiceExpand<T> {

    @SuppressWarnings("all")
    @Autowired
    protected M baseMapper;

    protected M getBaseMapper() {
        return baseMapper;
    }

    /**
     * 通过ID查询
     * @param id id
     * @return /
     */
    @Override
    public Optional<T> findById(ID id){
        T t = this.baseMapper.selectById(id);
        return t == null ? Optional.empty() : Optional.of(t);
    }

    /**
     * 通过id查询 ，如果没有则抛出 EntityNotFoundException
     * @param id id
     * @return /
     */
    @Override
    public T findByIdOrThrow(ID id){
        return this.findById(id).orElseThrow(EntityNotFoundException::new);
    }

    /**
     * 查询所有
     * @param query 查询条件可以为null
     * @return /
     */
    @Override
    public List<T> findAll(QueryWrapper<T> query){
        return this.baseMapper.selectList(query);
    }

    /**
     * 通过多个id查询
     * @param ids ids
     * @return /
     */
    @Override
    public List<T> findAllById(Collection<ID> ids){
        return this.baseMapper.selectBatchIds(ids);
    }

    /**
     * 查询分页
     * @param query 查询条件，可以为null
     * @param pageable 分页条件
     * @return /
     */
    @Override
    public Page<T> findAll(QueryWrapper<T> query, Page<T> pageable){
        return this.baseMapper.selectPage(pageable,query);
    }


    /**
     * 查询一个
     * @param query 查询条件，非空
     * @return /
     */
    @Override
    public Optional<T> findOne(@NotNull QueryWrapper<T> query){
        T t = this.baseMapper.selectOne(query);
        return t == null ? Optional.empty() : Optional.of(t);
    }

    /**
     * 查询一个，如果没有找到则抛出 EntityNotFoundException
     * @param query 查询条件，非空
     * @return /
     */
    @Override
    public T findOneOrThrow(@NotNull QueryWrapper<T> query){
        return this.findOne(query).orElseThrow(EntityNotFoundException::new);
    }

    /**
     * 新增一个实体
     * @param resource 资源实体
     * @return 新增后的实体
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public T create(T resource){
        try {
            this.createBefore(resource);
            this.baseMapper.insert(resource);
            this.createAfter(resource);
            return resource;
        } finally {
            this.clearContext();
        }
    }

    /**
     * 更新实体
     * @param resource 资源实体
     * @return 更新后的实体
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public T update(T resource) {
        try {
            T entity = this.findByIdOrThrow(resource.getId());
            this.updateBefore(entity, resource);
            this.updateProperty(entity, resource);
            this.baseMapper.updateById(entity);
            this.updateAfter(entity);
            return entity;
        } finally {
            this.clearContext();
        }
    }

    /**
     * 通过id删除
     * @param id id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(ID id) {
        try {
            T entity = this.findByIdOrThrow(id);
            this.deleteBefore(entity);
            this.baseMapper.deleteById(entity.getId());
            this.deleteAfter(entity);
        } finally {
            this.clearContext();
        }
    }

    /**
     * 通过多个id删除
     * @param ids 多个id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Collection<ID> ids) {
        try {
            List<T> list = this.findAllById(ids);
            if (list.size() != ids.size()) {
                throw new BadRequestException("参数异常！");
            }
            this.deleteBefore(list);
            this.baseMapper.deleteBatchIds(ids);
            this.deleteAfter(list);
        } finally {
            clearContext();
        }
    }

}
